package dse.messages.multiversion;

import java.util.LinkedList;

import dse.Cluster;
import dse.DataObject;
import dse.DataShare;
import dse.Experiment;
import dse.ExperimentRecorder;
import dse.Node;
import dse.messages.Message;
import dse.messages.MessageHandler;
import dse.messages.MessageSender;
import dse.messages.MessageType;
import dse.messages.MessageUtil;
import dse.messages.singleversion.ShareDownloader;

public class ShareUpdateV4ResponseMessageHandler extends MessageSender
		implements MessageHandler {
	private DataObject dobj;
	private int shareIndex;
	private boolean tranx;
	private boolean affirm;
	private ShareDownloader downloader;
	
	public ShareUpdateV4ResponseMessageHandler (Experiment experiment, DataObject dobj, int shareIndex,
			boolean tranx, boolean affirm, ShareDownloader downloader)
	{
		super(experiment);
		
		this.dobj = dobj;
		this.shareIndex = shareIndex;
		this.tranx = tranx;
		this.affirm = affirm;
		this.downloader = downloader;
	}

	@Override
	public boolean acceptMessage(Message message) {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public void messageInterupted(ExperimentRecorder recorder, Message message,
			double time) {
		// TODO Auto-generated method stub
		recorder.debug(this, "msgIntrpt: " + message, time);
		if(tranx)
			downloader.shareUpdateFailed(recorder, dobj, shareIndex, time);
	}

	@Override
	public void messageReceived(ExperimentRecorder recorder, Message message,
			double time) {
		// TODO Auto-generated method stub
		recorder.debug(this, "msgRcvd: " + message, time);
		if (message.messageType() != MessageType.ShareUpdateV4Response) {
			recorder.warn(
					"ShareUpdateV4ResponseMessageHandler recieved " + 
					message.messageType() + " message."
					);
			return;
		}			
		
		if(tranx)
		{
			if(affirm)
			{
				downloader.shareUpdated(recorder, message.from(), dobj, shareIndex, time);
			}
			else
			{
				downloader.shareUpdateFailed(recorder, dobj, shareIndex, time);
			}
		}
		else if(!affirm)
		{
			// What do we know about the share?
			Node receiver = message.to();
			
			// Does the receiver have the share?
			DataShare share = receiver.getDataShare(dobj);
			if (share != null)
			{
				// Then we need to send a new message BACK (thats why to and from
				// are reversed!
				LinkedList<Cluster> clusterRing = MessageUtil.getClustersRing(experiment.network(), 
						experiment.network().lookupCluster(receiver.clusterId()), dobj, experiment.modules().assigner());
				Cluster cluster = clusterRing.removeFirst();
				while(cluster != null)
				{
					if(message.from().clusterId() == cluster.id())
						break;
					cluster = clusterRing.removeFirst();
				}
					
				Node to = experiment.modules().assigner().assign(dobj, shareIndex, clusterRing.removeFirst());
				Message m = super.createShareUpdateV4Message(receiver, to, dobj, shareIndex, share.getLatest(), false, message.purpose(), downloader);
	
				recorder.debug(this, "new msg: " + m, time);
				experiment.messageQueue().enqueueMessage(m, time);
			}
		}
	}
}
